<template>
  <div class="dashboard">
    <!-- 页面头部 -->
    <div class="dashboard-header">
      <div class="header-content">
        <div class="header-left">
          <h1 class="page-title">
            <el-icon class="title-icon"><DataBoard /></el-icon>
            数据平台仪表板
          </h1>
          <p class="page-subtitle">实时监控数据平台运行状态和关键指标</p>
        </div>
        <div class="header-actions">
          <!-- 按需保留：按要求移除所有按钮 -->
        </div>
      </div>
      
      <!-- 系统状态指示器 -->
      <div class="system-status" v-if="systemStatus.status !== 'healthy'">
        <el-alert
          :title="systemStatus.message"
          :type="systemStatus.type"
          show-icon
          :closable="false"
          class="status-alert"
        />
      </div>
    </div>

    <!-- 常用模块（上移到关键指标概览上方） -->
    <div class="modules-section">
      <div class="section-header">
        <h2 class="section-title">常用模块</h2>
        <p class="section-desc">快速进入常用功能模块</p>
      </div>
      <el-row :gutter="24">
        <el-col :xs="24" :sm="12" :md="6">
          <div class="module-card clickable-card" @click="$router.push('/monitor/overview')">
            <div class="module-icon primary"><el-icon><DataBoard /></el-icon></div>
            <div class="module-title">数据监控</div>
            <div class="module-desc">总览与趋势、健康态势</div>
          </div>
        </el-col>
        <el-col :xs="24" :sm="12" :md="6">
          <div class="module-card clickable-card" @click="$router.push('/monitor/tables')">
            <div class="module-icon success"><el-icon><Document /></el-icon></div>
            <div class="module-title">数据列表</div>
            <div class="module-desc">按层浏览与筛选</div>
          </div>
        </el-col>
        <el-col :xs="24" :sm="12" :md="6">
          <div class="module-card clickable-card" @click="$router.push('/alert/rules')">
            <div class="module-icon warning"><el-icon><Warning /></el-icon></div>
            <div class="module-title">告警管理</div>
            <div class="module-desc">规则、历史与模板</div>
          </div>
        </el-col>
        <el-col :xs="24" :sm="12" :md="6">
          <div class="module-card clickable-card" @click="$router.push('/flink/jobs')">
            <div class="module-icon danger"><el-icon><Connection /></el-icon></div>
            <div class="module-title">Flink 作业</div>
            <div class="module-desc">作业运行与管理</div>
          </div>
        </el-col>
      </el-row>
    </div>

    <!-- 数据趋势分析（上移到常用模块下方） -->
    <div class="charts-section" style="margin-top: 16px;">
      <div class="section-header">
        <h2 class="section-title">数据趋势分析</h2>
        <p class="section-desc">可视化展示关键指标的变化趋势和分布情况</p>
            </div>
      
      <el-row :gutter="24" class="charts-row">
        <el-col :xs="24" :lg="12">
          <div class="chart-card">
            <div class="chart-header">
              <div class="chart-title">
                <h3>数据变化趋势</h3>
                <p class="chart-subtitle">最近7天数据量变化情况</p>
              </div>
              <div class="chart-actions">
                <el-select v-model="trendTimeRange" size="small" style="width: 120px">
                  <el-option label="7天" value="7d" />
                  <el-option label="30天" value="30d" />
                  <el-option label="90天" value="90d" />
                </el-select>
              </div>
            </div>
          
          <div class="chart-container">
            <TrendChart
              :data="trendData"
                title="数据变化趋势"
                :height="320"
            />
          </div>
          </div>
      </el-col>
      
        <el-col :xs="24" :lg="12">
          <div class="chart-card">
            <div class="chart-header">
              <div class="chart-title">
                <h3>告警分布统计</h3>
                <p class="chart-subtitle">今日各类告警的分布情况</p>
            </div>
              <div class="chart-actions">
                <el-button size="small" @click="refreshAlertData">
                  <el-icon><Refresh /></el-icon>
                </el-button>
              </div>
            </div>
          
          <div class="chart-container">
            <AlertChart
              :data="alertData"
                title="告警分布"
                :height="320"
            />
          </div>
          </div>
      </el-col>
    </el-row>
    </div>

    <!-- 统计卡片 -->
    <div class="stats-section" style="margin-top: 16px;">
      <div class="section-header">
        <h2 class="section-title">关键指标概览</h2>
        <p class="section-desc">实时展示平台核心运行指标</p>
      </div>
      
      <el-row :gutter="24" class="stats-row">
        <el-col :xs="24" :sm="12" :md="6" v-for="(stat, index) in statsList" :key="stat.key">
          <div 
            class="stat-card" 
            :class="[`stat-${stat.status}`, 'clickable-card']"
            @click="handleCardClick(stat.module)"
          >
            <div class="stat-icon" :style="{ backgroundColor: stat.color + '20' }">
              <el-icon :size="24" :style="{ color: stat.color }">
                <component :is="stat.icon" />
              </el-icon>
            </div>
            <div class="stat-content">
              <div class="stat-value">
                {{ stat.value }}
                <span v-if="stat.unit" class="stat-unit">{{ stat.unit }}</span>
              </div>
              <div class="stat-title">{{ stat.title }}</div>
              <div class="stat-trend" v-if="stat.trend">
                <el-icon v-if="stat.trend === 'up'" class="trend-up"><ArrowUp /></el-icon>
                <el-icon v-else-if="stat.trend === 'down'" class="trend-down"><ArrowDown /></el-icon>
                <span class="trend-text">{{ stat.trendText }}</span>
              </div>
            </div>
          </div>
      </el-col>
    </el-row>
    </div>

    <!-- 数据层概览 -->
    <div class="layers-section">
      <div class="section-header">
        <h2 class="section-title">数据层健康状态</h2>
        <p class="section-desc">监控各数据层的运行状态和资源使用情况</p>
            </div>
          
      <el-row :gutter="24" class="layers-row">
            <el-col 
          :xs="24" :sm="12" :md="8" :lg="4" 
              v-for="layer in dashboardStats.layers" 
              :key="layer.layer" 
            >
              <div class="layer-card" :class="`layer-${layer.layer.toLowerCase()}`" @click="gotoLayer(layer.layer)">
                <div class="layer-header">
              <div class="layer-title">
                  <h3>{{ layer.layer }}层</h3>
                <span class="layer-desc">{{ getLayerDescription(layer.layer) }}</span>
              </div>
                  <div class="layer-status" :class="layer.health_status">
                    <el-icon v-if="layer.health_status === 'healthy'"><CircleCheck /></el-icon>
                    <el-icon v-else-if="layer.health_status === 'warning'"><Warning /></el-icon>
                    <el-icon v-else><CircleClose /></el-icon>
                  </div>
                </div>
                
                <div class="layer-stats">
                  <div class="stat-item">
                <div class="stat-icon">
                  <el-icon><Document /></el-icon>
                  </div>
                <div class="stat-content">
                  <span class="stat-value">{{ layer.table_count }}</span>
                  <span class="stat-label">表数量</span>
                </div>
              </div>
              
                  <div class="stat-item">
                <div class="stat-icon">
                  <el-icon><DataAnalysis /></el-icon>
                  </div>
                <div class="stat-content">
                  <span class="stat-value">{{ formatDataSize(layer.total_size) }}</span>
                  <span class="stat-label">数据量</span>
                </div>
              </div>
              
                  <div class="stat-item">
                <div class="stat-icon">
                  <el-icon><Connection /></el-icon>
                </div>
                <div class="stat-content">
                  <span class="stat-value">{{ formatNumber(layer.total_rows) }}</span>
                  <span class="stat-label">总行数</span>
                </div>
                  </div>
                </div>
                
                <div class="layer-footer">
              <div class="health-indicator" :class="layer.health_status">
                <span class="health-text">{{ getHealthStatusText(layer.health_status) }}</span>
              </div>
              <span class="update-time">{{ formatRelativeTime(layer.last_update) }}</span>
                </div>
              </div>
            </el-col>
          </el-row>
    </div>

    <!-- 最近告警 -->
    <div class="alerts-section">
      <div class="section-header">
        <h2 class="section-title">最近告警</h2>
        <p class="section-desc">实时监控系统告警状态，及时处理异常情况</p>
      </div>
      
      <div class="alerts-card">
        <div class="alerts-header">
          <div class="alerts-summary">
            <div class="summary-item is-total summary-link" @click="$router.push('/alert/history')">
              <div class="summary-icon total"><el-icon><Document /></el-icon></div>
              <div class="summary-meta">
                <span class="summary-label">总告警数</span>
                <span class="summary-value">{{ recentAlerts.length }}</span>
              </div>
            </div>
            <div class="summary-item is-active summary-link" @click="$router.push({ path: '/alert/history', query: { status: 'ACTIVE' } })">
              <div class="summary-icon active"><el-icon><Warning /></el-icon></div>
              <div class="summary-meta">
                <span class="summary-label">活跃告警</span>
                <span class="summary-value">{{ getActiveAlertsCount() }}</span>
              </div>
            </div>
            <div class="summary-item is-resolved summary-link" @click="$router.push({ path: '/alert/history', query: { status: 'RESOLVED' } })">
              <div class="summary-icon resolved"><el-icon><CircleCheck /></el-icon></div>
              <div class="summary-meta">
                <span class="summary-label">已解决</span>
                <span class="summary-value">{{ getResolvedAlertsCount() }}</span>
              </div>
            </div>
          </div>
        </div>

        <!-- 自动轮播Ticker -->
        <div class="alerts-ticker" @mouseenter="pauseTicker" @mouseleave="resumeTicker">
          <div class="ticker-viewport">
            <transition-group name="ticker" tag="div">
              <div v-for="item in tickerVisible" :key="item.id + '-' + item.triggered_at" class="ticker-row">
                <div class="ticker-time">
                  <div class="time-main">{{ formatTime(item.triggered_at) }}</div>
                  <div class="time-relative">{{ formatRelativeTime(item.triggered_at) }}</div>
                </div>
                <el-tag :type="getSeverityType(item.severity)" size="small" :class="`severity-${item.severity.toLowerCase()}`">
                  {{ getSeverityText(item.severity) }}
                </el-tag>
                <div class="ticker-title">
                  <span class="title-text">{{ item.title }}</span>
                  <span v-if="item.content" class="title-desc">{{ item.content }}</span>
                </div>
                <el-tag :type="getStatusType(item.status)" size="small" :class="`status-${item.status.toLowerCase()}`">
                  {{ getStatusText(item.status) }}
                </el-tag>
                <el-button type="text" size="small" @click="viewAlert(item)">查看</el-button>
              </div>
            </transition-group>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, computed, watch } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { 
  DataBoard, 
  DataAnalysis, 
  Warning, 
  Connection, 
  Document, 
  Refresh, 
  Download, 
  CircleCheck, 
  CircleClose, 
  ArrowUp, 
  ArrowDown,
  InfoFilled
} from '@element-plus/icons-vue'
import DashboardCard from '@/components/DashboardCard.vue'
import TrendChart from '@/components/TrendChart.vue'
import AlertChart from '@/components/AlertChart.vue'
import type { DashboardStats, AlertHistory } from '@/types'

const router = useRouter()

// 页面状态
const refreshing = ref(false)
const alertsLoading = ref(false)

// 系统状态
const systemStatus = ref({
  status: 'healthy',
  message: '系统运行正常',
  type: 'success'
})

// 趋势时间范围
const trendTimeRange = ref('7d')

// 仪表板数据
const dashboardStats = ref<DashboardStats>({
  total_tables: 0,
  total_data_size: 0,
  active_alerts: 0,
  running_jobs: 0,
  layers: []
})

// 统计卡片列表
const statsList = computed(() => [
  {
    key: 'tables',
    title: '监控表总数',
    value: dashboardStats.value.total_tables,
    unit: '个',
    icon: DataBoard,
    color: '#409EFF',
    status: 'normal',
    trend: 'up',
    trendText: '+12%',
    module: 'monitor'
  },
  {
    key: 'dataSize',
    title: '总数据量',
    value: formatDataSize(dashboardStats.value.total_data_size),
    icon: DataAnalysis,
    color: '#67C23A',
    status: 'normal',
    trend: 'up',
    trendText: '+8%',
    module: 'monitor'
  },
  {
    key: 'alerts',
    title: '活跃告警',
    value: dashboardStats.value.active_alerts,
    unit: '个',
    icon: Warning,
    color: '#E6A23C',
    status: dashboardStats.value.active_alerts > 0 ? 'warning' : 'normal',
    trend: dashboardStats.value.active_alerts > 0 ? 'up' : 'down',
    trendText: dashboardStats.value.active_alerts > 0 ? '+3' : '-2',
    module: 'alert'
  },
  {
    key: 'jobs',
    title: '运行中作业',
    value: dashboardStats.value.running_jobs,
    unit: '个',
    icon: Connection,
    color: '#F56C6C',
    status: 'normal',
    trend: 'stable',
    trendText: '稳定',
    module: 'flink'
  }
])

// 趋势数据
const trendData = ref([
  { time: '2024-01-09', value: 1000000 },
  { time: '2024-01-10', value: 1200000 },
  { time: '2024-01-11', value: 1100000 },
  { time: '2024-01-12', value: 1300000 },
  { time: '2024-01-13', value: 1250000 },
  { time: '2024-01-14', value: 1400000 },
  { time: '2024-01-15', value: 1500000 }
])

// 告警数据
const alertData = ref([
  { name: '数据量异常', value: 5 },
  { name: 'Flink作业失败', value: 3 },
  { name: '数据延迟', value: 2 },
  { name: '系统异常', value: 1 }
])

// 最近告警
const recentAlerts = ref<AlertHistory[]>([])

// 模拟数据
const mockData = () => {
  dashboardStats.value = {
    total_tables: 1234,
    total_data_size: 2048576000,
    active_alerts: 12,
    running_jobs: 18,
    layers: [
      { layer: 'TDS', table_count: 12, total_rows: 500000000, total_size: 204857600, health_status: 'healthy', last_update: '2024-01-15T10:30:00Z' },
      { layer: 'ODS', table_count: 45, total_rows: 2000000000, total_size: 819430400, health_status: 'warning', last_update: '2024-01-15T10:25:00Z' },
      { layer: 'DWD', table_count: 32, total_rows: 1000000000, total_size: 409715200, health_status: 'healthy', last_update: '2024-01-15T10:28:00Z' },
      { layer: 'DWS', table_count: 18, total_rows: 500000000, total_size: 204857600, health_status: 'healthy', last_update: '2024-01-15T10:32:00Z' },
      { layer: 'DIM', table_count: 25, total_rows: 200000000, total_size: 81943040, health_status: 'healthy', last_update: '2024-01-15T10:35:00Z' },
      { layer: 'ADS', table_count: 15, total_rows: 100000000, total_size: 40971520, health_status: 'healthy', last_update: '2024-01-15T10:38:00Z' }
    ]
  }

  recentAlerts.value = [
    { id: 1, alert_type: 'data_volume', title: '数据量异常告警', content: '表 tds_by_talent_baiying_from_dyh 数据量超过阈值', severity: 'HIGH', status: 'ACTIVE', triggered_at: '2024-01-15T10:30:00Z', notification_sent: true },
    { id: 2, alert_type: 'job_failure', title: 'Flink作业失败告警', content: '作业 Api_Job_Kafka2SR_TDS 执行失败', severity: 'CRITICAL', status: 'RESOLVED', triggered_at: '2024-01-15T09:15:00Z', resolved_at: '2024-01-15T09:30:00Z', notification_sent: true }
  ]
}

// 刷新数据
const refreshData = async () => {
  refreshing.value = true
  try {
    await mockData()
    ElMessage.success('数据刷新完成')
  } catch (error) {
    ElMessage.error('数据刷新失败')
  } finally {
    refreshing.value = false
  }
}

// 导出仪表板报告
const exportDashboard = () => {
  ElMessage.info('导出功能开发中...')
}

// 刷新告警数据
const refreshAlertData = () => {}

// 刷新告警列表
const refreshAlerts = async () => {
  alertsLoading.value = true
  try {
    await new Promise(resolve => setTimeout(resolve, 1000))
    mockData()
    ElMessage.success('告警数据刷新完成')
  } catch (error) {
    ElMessage.error('告警数据刷新失败')
  } finally {
    alertsLoading.value = false
  }
}

// 层跳转
const gotoLayer = (layer: string) => {
  router.push({ path: '/monitor/tables', query: { layer } })
}

// 获取活跃告警数量
const getActiveAlertsCount = () => recentAlerts.value.filter(alert => alert.status === 'ACTIVE').length

// 获取已解决告警数量
const getResolvedAlertsCount = () => recentAlerts.value.filter(alert => alert.status === 'RESOLVED').length

// 获取告警行样式类
const getAlertRowClass = ({ row }: { row: AlertHistory }) => {
  if (row.status === 'ACTIVE') return 'alert-row-active'
  if (row.severity === 'CRITICAL') return 'alert-row-critical'
  return ''
}

// 查看告警详情
const viewAlert = (alert: AlertHistory) => {
  router.push(`/alert/history?id=${alert.id}`)
}

// 处理卡片点击跳转
const handleCardClick = (module: string) => {
  switch (module) {
    case 'monitor':
      router.push('/monitor/tables')
      break
    case 'alert':
      router.push('/alert/rules')
      break
    case 'flink':
      router.push('/flink/jobs')
      break
    default:
      break
  }
}

// 工具函数（保持不变）
const formatDataSize = (bytes: number): string => {
  const MB = 1024 * 1024
  const GB = MB * 1024
  const TB = GB * 1024
  if (!bytes || bytes <= 0) return '0 MB'
  if (bytes >= TB) return (bytes / TB).toFixed(2) + ' T'
  if (bytes >= GB) return (bytes / GB).toFixed(2) + ' GB'
  // 最小单位按 MB 展示
  return (bytes / MB).toFixed(2) + ' MB'
}

const formatNumber = (num: number): string => {
  if (num == null || isNaN(num as any)) return '0'
  // >= 1亿：以 “X亿Y百万” 展示（Y按百万取整）
  if (num >= 100_000_000) {
    const yi = Math.floor(num / 100_000_000)
    const remainder = num - yi * 100_000_000
    const baiwan = Math.floor(remainder / 1_000_000)
    return baiwan > 0 ? `${yi}亿${baiwan}百万` : `${yi}亿`
  }
  // < 1亿：以“万”为单位展示
  if (num >= 10_000) {
    const wan = Math.round(num / 10_000)
    return `${wan}万`
  }
  return num.toString()
}

const formatTime = (time: string): string => new Date(time).toLocaleString('zh-CN')

const formatRelativeTime = (time: string): string => {
  const now = new Date(); const target = new Date(time)
  const diff = now.getTime() - target.getTime()
  const minutes = Math.floor(diff / 60000)
  const hours = Math.floor(diff / 3600000)
  const days = Math.floor(diff / 86400000)
  if (minutes < 1) return '刚刚'
  if (minutes < 60) return `${minutes}分钟前`
  if (hours < 24) return `${hours}小时前`
  if (days < 7) return `${days}天前`
  return target.toLocaleDateString('zh-CN')
}

const getLayerDescription = (layer: string): string => {
  const descriptions: Record<string, string> = { 'TDS': '原始数据采集', 'ODS': '操作数据存储', 'DWD': '明细数据仓库', 'DWS': '汇总数据服务', 'DIM': '维度数据管理', 'ADS': '应用数据服务' }
  return descriptions[layer] || '数据层'
}

const getHealthStatusText = (status: string): string => {
  const texts: Record<string, string> = { 'healthy': '健康', 'warning': '警告', 'error': '错误' }
  return texts[status] || '未知'
}

const getSeverityType = (severity: string): string => {
  const types: Record<string, string> = { 'LOW': 'info', 'MEDIUM': 'warning', 'HIGH': 'danger', 'CRITICAL': 'danger' }
  return types[severity] || 'info'
}

const getSeverityText = (severity: string): string => {
  const texts: Record<string, string> = { 'LOW': '低', 'MEDIUM': '中', 'HIGH': '高', 'CRITICAL': '严重' }
  return texts[severity] || severity
}

const getStatusType = (status: string): string => {
  const types: Record<string, string> = { 'ACTIVE': 'danger', 'RESOLVED': 'success', 'ACKNOWLEDGED': 'warning' }
  return types[status] || 'info'
}

const getStatusText = (status: string): string => {
  const texts: Record<string, string> = { 'ACTIVE': '活跃', 'RESOLVED': '已解决', 'ACKNOWLEDGED': '已确认' }
  return texts[status] || status
}

// 轮播Ticker
const tickerInterval = ref<number | null>(null)
const isPaused = ref(false)
const tickerIndex = ref(0)
const tickerPageSize = 4
const tickerVisible = computed(() => {
  const start = tickerIndex.value
  const end = start + tickerPageSize
  const list = recentAlerts.value
  if (!list.length) return []
  const slice = list.concat(list).slice(start, end) // 循环
  return slice
})

const startTicker = () => {
  stopTicker()
  tickerInterval.value = window.setInterval(() => {
    if (isPaused.value) return
    tickerIndex.value = (tickerIndex.value + 1) % Math.max(recentAlerts.value.length, 1)
  }, 2500)
}
const stopTicker = () => { if (tickerInterval.value) { clearInterval(tickerInterval.value); tickerInterval.value = null } }
const pauseTicker = () => { isPaused.value = true }
const resumeTicker = () => { isPaused.value = false }

watch(() => recentAlerts.value.length, () => { tickerIndex.value = 0; startTicker() })

onMounted(() => {
  mockData()
  startTicker()
})
</script>

<style scoped>
/* 统一卡片视觉：低对比、柔和阴影、细分隔 */
.dashboard { padding: 20px; background: linear-gradient(135deg, #f7f8fa 0%, #eceff3 100%); min-height: 100vh; }

/* 丰富头部卡片色彩：淡蓝渐变 + 顶部彩带 */
.dashboard-header { background: linear-gradient(180deg, #f6fbff 0%, #f0f6ff 100%); border-radius: 16px; padding: 20px; margin-bottom: 20px; box-shadow: 0 4px 16px rgba(31,35,41,0.06); border: 1px solid #e3edf9; position: relative; overflow: hidden; }
.dashboard-header::before { content: ''; position: absolute; left: 0; top: 0; right: 0; height: 4px; background: linear-gradient(90deg, #60a5fa 0%, #34d399 33%, #f59e0b 66%, #ef4444 100%); opacity: .9; }
.header-content { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.page-title { display: flex; align-items: center; margin: 0 0 8px 0; font-size: 26px; font-weight: 800; color: #0f172a; }
.title-icon { margin-right: 12px; color: #409EFF; font-size: 28px; }
.page-subtitle { margin: 0 0 0 40px; font-size: 14px; color: #475569; }
.header-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.status-alert { border-radius: 8px; }

.intro-section { margin-bottom: 16px; }
/* 丰富平台介绍卡片色彩：淡青渐变 + 左侧强调边 */
.intro-card { display: flex; justify-content: space-between; gap: 16px; background: linear-gradient(180deg, #f3fffb 0%, #ecfff7 100%); border-radius: 12px; border: 1px solid #d9f5ea; box-shadow: 0 4px 16px rgba(31,35,41,0.06); padding: 16px; position: relative; overflow: hidden; }
.intro-card::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: linear-gradient(180deg, #10b981 0%, #34d399 100%); }
.intro-left h2 { margin: 0 0 6px 0; font-size: 20px; color: #065f46; }
.intro-left p, .intro-list { color: #0f766e; }
.intro-list { margin: 6px 0 0 18px; font-size: 13px; }

.stats-section { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 16px; box-shadow: 0 4px 16px rgba(31,35,41,0.06); border: 1px solid #eef0f3; }
.section-header { margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px dashed #eef0f3; }
.section-title { margin: 0 0 6px 0; font-size: var(--font-title); font-weight: 700; color: #1f2937; display: flex; align-items: center; }
.section-title::before { content: ''; width: 4px; height: 18px; background: linear-gradient(180deg, #5aa8ff 0%, #3a78ff 100%); border-radius: 2px; margin-right: 10px; }
.section-desc { margin: 0; font-size: var(--font-body); color: #6b7280; }

/* 统计卡片 */
.stat-card { display: flex; align-items: center; padding: 16px; background: linear-gradient(180deg, #ffffff 0%, #fafbfc 100%); border-radius: 12px; border: 1px solid #eff2f6; transition: transform .18s ease, box-shadow .18s ease; cursor: pointer; min-height: 104px; position: relative; overflow: hidden; }
.stat-card:hover { transform: translateY(-4px); box-shadow: 0 10px 24px rgba(31,35,41,0.08); border-color: #dfe7f3; }
.stat-icon { width: 44px; height: 44px; border-radius: 12px; background: #f3f6fb; display: flex; align-items: center; justify-content: center; margin-right: 16px; box-shadow: inset 0 0 0 2px #e6eef9; }
.stat-value { font-size: 22px; font-weight: 700; color: #111827; margin-bottom: 4px; display: flex; align-items: baseline; gap: 6px; }
.stat-unit { font-size: 12px; color: #6b7280; }
.stat-title { font-size: 13px; color: #6b7280; margin-bottom: 6px; }
.stat-trend { display: flex; align-items: center; gap: 4px; font-size: 12px; padding: 2px 8px; background: #f6f7f9; border-radius: 12px; width: fit-content; }

/* 数据层卡片 - 强化信息层次与图标环形视觉 */
.layers-section, .modules-section, .charts-section, .alerts-section { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 16px; box-shadow: 0 4px 16px rgba(31,35,41,0.06); border: 1px solid #eef0f3; }
.layer-card { padding: 16px; min-height: 180px; border-radius: 12px; border: 1px solid #eff2f6; background: linear-gradient(180deg, #ffffff 0%, #fafcfe 100%); transition: transform .18s ease, box-shadow .18s ease; }
.layer-card:hover { transform: translateY(-3px); box-shadow: 0 10px 24px rgba(31,35,41,0.08); }
.layers-row .el-col { margin-bottom: 12px; }
.layer-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
.layer-title h3 { font-size: 16px; margin: 0; }
.layer-desc { font-size: 12px; color: #6b7280; word-break: break-all; }
.layer-status { display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; box-shadow: inset 0 0 0 2px #e6eef9; }
.layer-status.healthy { color: #22c55e; box-shadow: inset 0 0 0 2px #bbf7d0; }
.layer-status.warning { color: #f59e0b; box-shadow: inset 0 0 0 2px #fde68a; }
.layer-status.error { color: #ef4444; box-shadow: inset 0 0 0 2px #fecaca; }

.layer-stats { display: grid; grid-template-columns: 1fr; gap: 8px; margin-bottom: 8px; }
.stat-item { display: flex; align-items: center; gap: 10px; padding: 8px; border: 1px dashed #eef2f7; border-radius: 10px; background: #fcfdff; }
.stat-item .stat-icon { width: 32px; height: 32px; border-radius: 10px; background: #f2f5fa; box-shadow: inset 0 0 0 2px #e6eef9; }
.stat-item .stat-value { font-size: 15px; color: #111827; }
.stat-item .stat-label { font-size: 12px; color: #6b7280; }
.layer-footer { display: flex; justify-content: space-between; align-items: center; padding-top: 8px; border-top: 1px dashed #eef2f7; }
.health-indicator { padding: 4px 8px; border-radius: 12px; font-size: 12px; font-weight: 600; background: #f3f6fb; color: #409eff; }
.health-indicator.warning { background: #fff7ed; color: #f59e0b; }
.health-indicator.error { background: #fef2f2; color: #ef4444; }
.update-time { font-size: 11px; color: #6b7280; }

/* 常用模块卡片 - 图标色块 + 标题/说明对齐 */
.module-card { padding: 16px; min-height: 100px; height: auto; border: 1px solid #eff2f6; border-radius: 12px; background: linear-gradient(180deg, #ffffff 0%, #fafcfe 100%); transition: transform .18s ease, box-shadow .18s ease; display: flex; flex-direction: column; gap: 8px; }
.module-card:hover { transform: translateY(-3px); box-shadow: 0 10px 24px rgba(31,35,41,0.08); }
.module-icon { width: 32px; height: 32px; border-radius: 10px; display: flex; align-items: center; justify-content: center; color: #fff; box-shadow: 0 6px 12px rgba(31,35,41,0.12); }
.module-icon.primary { background: linear-gradient(180deg, #60a5fa 0%, #3b82f6 100%); }
.module-icon.success { background: linear-gradient(180deg, #34d399 0%, #10b981 100%); }
.module-icon.warning { background: linear-gradient(180deg, #fbbf24 0%, #f59e0b 100%); }
.module-icon.danger { background: linear-gradient(180deg, #f87171 0%, #ef4444 100%); }
.module-title { font-weight: 700; color: #111827; }
.module-desc { font-size: 12px; color: #6b7280; }

/* 图表/告警区：防止图表内容溢出与下方重叠 */
.chart-card { min-height: 360px; padding: 16px; background: #fff; border: 1px solid #eff2f6; border-radius: 12px; overflow: hidden; position: relative; }
.chart-container { height: 300px; overflow: hidden; }

.alerts-header { margin-bottom: 16px; padding-bottom: 12px; }
.alerts-summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; align-items: stretch; }
.summary-item { display: flex; align-items: center; gap: 12px; padding: 10px 14px; border-radius: 10px; background: #fff; border: 1px solid #eef2f7; transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease; }
.summary-link { cursor: pointer; }
.summary-link:hover { border-color: #dbe4f3; transform: translateY(-2px); box-shadow: 0 6px 14px rgba(31,35,41,0.06); }

/* 丰富配色：为不同类型卡片提供浅色背景和边框色 */
.summary-item.is-total { background: linear-gradient(180deg, #f7f7f8 0%, #f1f2f4 100%); border-color: #e5e7eb; }
.summary-item.is-active { background: linear-gradient(180deg, #fff7e6 0%, #fff1d6 100%); border-color: #ffe5b4; }
.summary-item.is-resolved { background: linear-gradient(180deg, #e8fff5 0%, #dffcef 100%); border-color: #b7f5d9; }
.summary-item.is-total .summary-label { color: #6b7280; }
.summary-item.is-active .summary-label { color: #b45309; }
.summary-item.is-resolved .summary-label { color: #047857; }

.summary-icon { width: 32px; height: 32px; border-radius: 10px; display: flex; align-items: center; justify-content: center; color: #fff; }
.summary-icon.total { background: linear-gradient(180deg, #9ca3af 0%, #6b7280 100%); }
.summary-icon.active { background: linear-gradient(180deg, #fbbf24 0%, #f59e0b 100%); }
.summary-icon.resolved { background: linear-gradient(180deg, #34d399 0%, #10b981 100%); }
.summary-meta { display: flex; flex-direction: column; line-height: 1.1; }
.summary-label { font-size: 12px; color: #6b7280; }
.summary-value { font-size: 22px; font-weight: 800; color: #111827; }
.summary-item.is-active .summary-value { color: #b45309; }
.summary-item.is-resolved .summary-value { color: #047857; }

/* Ticker 动画与样式 */
.alerts-ticker { max-height: 240px; overflow: hidden; border-top: 1px dashed #eef2f7; padding-top: 10px; }
.ticker-viewport { position: relative; }
.ticker-row { display: grid; grid-template-columns: 160px 80px 1fr 90px 60px; align-items: center; gap: 12px; padding: 8px 0; border-bottom: 1px dotted #f0f2f5; }
.ticker-time { display: flex; flex-direction: column; gap: 2px; }
.ticker-enter-active, .ticker-leave-active { transition: all .4s ease; }
.ticker-enter-from { opacity: 0; transform: translateY(12px); }
.ticker-leave-to { opacity: 0; transform: translateY(-12px); position: absolute; }

/* 数据层卡片 - 强化“数据量”这一行（第二行）展示效果 */
.layer-card .layer-stats .stat-item:nth-child(2) {
  background: linear-gradient(180deg, #f6faff 0%, #f2f7ff 100%);
  border: 1px solid #dbe9ff;
  box-shadow: 0 6px 16px rgba(64, 158, 255, 0.08);
}
.layer-card .layer-stats .stat-item:nth-child(2) .stat-icon {
  background: linear-gradient(180deg, #5aa8ff 0%, #3b82f6 100%);
  color: #fff;
  box-shadow: 0 6px 12px rgba(59, 130, 246, 0.25);
}
.layer-card .layer-stats .stat-item:nth-child(2) .stat-value {
  color: #2563eb;
  font-size: 18px;
  font-weight: 800;
  letter-spacing: 0.2px;
  font-variant-numeric: tabular-nums; /* 数字等宽，读数更稳 */
}
.layer-card .layer-stats .stat-item:nth-child(2) .stat-label {
  color: #5b77a4;
}

/* 细节：hover 微动画，避免突兀 */
.layer-card .layer-stats .stat-item:nth-child(2):hover {
  transform: translateY(-1px);
  transition: transform .15s ease, box-shadow .15s ease;
  box-shadow: 0 10px 24px rgba(59, 130, 246, 0.12);
}

/* 关键指标卡片配色：根据图标主色设置淡色背景 */
.stat-card { display: flex; align-items: center; padding: 16px; border-radius: 12px; border: 1px solid #eff2f6; transition: transform .18s ease, box-shadow .18s ease; min-height: 104px; background: #fff; }
.stat-card:hover { transform: translateY(-4px); box-shadow: 0 10px 24px rgba(31,35,41,0.08); }
.stat-card.stat-normal { border-left: 4px solid #409EFF; background: linear-gradient(180deg, #f0f7ff 0%, #e9f3ff 100%); }
.stat-card.stat-warning { border-left: 4px solid #e6a23c; background: linear-gradient(180deg, #fff6e9 0%, #fff0d9 100%); }
.stat-card.stat-danger { border-left: 4px solid #f56c6c; background: linear-gradient(180deg, #ffecec 0%, #ffe5e5 100%); }
.stat-card.stat-success { border-left: 4px solid #67c23a; background: linear-gradient(180deg, #effbf2 0%, #e6f7ed 100%); }
.stat-icon { width: 44px; height: 44px; border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-right: 16px; box-shadow: inset 0 0 0 2px #e6eef9; background: #f3f6fb; }

/* 数据层卡片配色：沿用各层主题色的淡色背景 */
.layer-card { padding: 24px; border-radius: 16px; border: 1px solid #eef0f3; background: #fff; transition: transform .18s ease, box-shadow .18s ease; }
.layer-card:hover { transform: translateY(-6px); box-shadow: 0 10px 28px rgba(0,0,0,0.12); }
.layer-tds { --layer-color: #FF9F43; --layer-color-light: #FFE9D0; }
.layer-ods { --layer-color: #FF6B6B; --layer-color-light: #FFD9D9; }
.layer-dwd { --layer-color: #4ECDC4; --layer-color-light: #D8F7F4; }
.layer-dws { --layer-color: #45B7D1; --layer-color-light: #D6F1FB; }
.layer-dim { --layer-color: #A55EEA; --layer-color-light: #EDD9FF; }
.layer-ads { --layer-color: #96CEB4; --layer-color-light: #E4F6EC; }
.layer-card { background: linear-gradient(180deg, var(--layer-color-light) 0%, #ffffff 40%); border-left: 4px solid var(--layer-color); }
.layer-title h3 { color: var(--layer-color); }

/* 常用模块卡片配色 */
.module-card { background: linear-gradient(180deg, #ffffff 0%, #fafcfe 100%); border: 1px solid #eef2f6; border-radius: 12px; padding: 20px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; transition: transform .18s ease, box-shadow .18s ease; }
.module-card:hover { transform: translateY(-4px); box-shadow: 0 8px 20px rgba(0,0,0,0.08); }
.module-icon.primary { background: linear-gradient(180deg, #60a5fa 0%, #3b82f6 100%); box-shadow: 0 8px 16px rgba(59,130,246,.25); }
.module-icon.success { background: linear-gradient(180deg, #34d399 0%, #10b981 100%); box-shadow: 0 8px 16px rgba(16,185,129,.25); }
.module-icon.warning { background: linear-gradient(180deg, #fbbf24 0%, #f59e0b 100%); box-shadow: 0 8px 16px rgba(245,158,11,.25); }
.module-icon.danger { background: linear-gradient(180deg, #f87171 0%, #ef4444 100%); box-shadow: 0 8px 16px rgba(239,68,68,.25); }

@media (max-width: 1200px) {
  .page-title { font-size: 22px; }
  .title-icon { font-size: 24px; }
  .stat-card { min-height: 96px; }
  .stat-value { font-size: 20px; }
}

@media (max-width: 768px) {
  .dashboard { padding: 16px; }
  .stat-card { min-height: 88px; padding: 12px; }
  .stat-icon { width: 36px; height: 36px; margin-right: 12px; }
  .stat-value { font-size: 18px; }
}
</style> 